/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bff.core.manager;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.inspur.edp.bef.api.action.VoidActionResult;
import com.inspur.edp.bef.api.lcp.AuthInfo;
import com.inspur.edp.bef.api.lcp.IStandardLcp;
import com.inspur.edp.bef.api.parameter.retrieve.RetrieveParam;
import com.inspur.edp.bef.core.session.FuncSession;
import com.inspur.edp.bef.core.session.FuncSessionManager;
import com.inspur.edp.bef.core.session.distributed.EditableBefSessionManager;
import com.inspur.edp.bff.api.attribute.AbstractSourceConfig;
import com.inspur.edp.bff.api.dataprocessor.IChangeConvertor;
import com.inspur.edp.bff.api.dataprocessor.IDataConvertor;
import com.inspur.edp.bff.api.dataprocessor.IDefaultValueConvertor;
import com.inspur.edp.bff.api.dataprocessor.IEntityPropertyMapper;
import com.inspur.edp.bff.api.dataprocessor.IFilterFieldConvertor;
import com.inspur.edp.bff.api.exception.BffFrameworkException;
import com.inspur.edp.bff.api.exception.ErrorCodes;
import com.inspur.edp.bff.api.extend.IBffEntityDataExtend;
import com.inspur.edp.bff.api.extend.IBffEntityExtend;
import com.inspur.edp.bff.api.extend.IBffManagerExtend;
import com.inspur.edp.bff.api.manager.IFSManager;
import com.inspur.edp.bff.api.manager.IFSManagerContext;
import com.inspur.edp.bff.api.manager.QueryResult;
import com.inspur.edp.bff.api.manager.assembler.IAssemblerManager;
import com.inspur.edp.bff.api.manager.context.ChangeMapperContext;
import com.inspur.edp.bff.api.manager.context.TimeStampContext;
import com.inspur.edp.bff.api.param.retrieve.RetrieveChildResult;
import com.inspur.edp.bff.api.param.retrieve.RetrieveResult;
import com.inspur.edp.bff.core.action.FSActionFactory;
import com.inspur.edp.bff.core.action.cancel.CancelAction;
import com.inspur.edp.bff.core.action.delete.DeleteAction;
import com.inspur.edp.bff.core.action.delete.DeleteAndSaveAction;
import com.inspur.edp.bff.core.action.delete.DeleteChildAction;
import com.inspur.edp.bff.core.action.delete.MultiDeleteAction;
import com.inspur.edp.bff.core.action.modify.ModifyAction;
import com.inspur.edp.bff.core.action.query.QueryAction;
import com.inspur.edp.bff.core.action.query.QueryChildAction;
import com.inspur.edp.bff.core.action.query.QueryChildWithCodeAction;
import com.inspur.edp.bff.core.action.query.QueryWithAuthInfoAction;
import com.inspur.edp.bff.core.action.retrieve.EditAction;
import com.inspur.edp.bff.core.action.retrieve.MultiRetrieveAction;
import com.inspur.edp.bff.core.action.retrieve.RetrieveAction;
import com.inspur.edp.bff.core.action.retrieve.RetrieveChildAction;
import com.inspur.edp.bff.core.action.retrieve.RetrieveChildAndChildAction;
import com.inspur.edp.bff.core.action.retrieve.RetrieveChildByIndexAction;
import com.inspur.edp.bff.core.action.retrieve.RetrieveWithChildPaginationAction;
import com.inspur.edp.bff.core.action.retrievedefault.MulitRetrieveDefaultWtihDefaultValueAction;
import com.inspur.edp.bff.core.action.retrievedefault.RetrieveDefaultAction;
import com.inspur.edp.bff.core.action.retrievedefault.RetrieveDefaultBatchAction;
import com.inspur.edp.bff.core.action.retrievedefault.RetrieveDefaultChildAction;
import com.inspur.edp.bff.core.action.retrievedefault.RetrieveDefaultChildWithDefaultValueAtion;
import com.inspur.edp.bff.core.action.retrievedefault.RetrieveDefaultChildWithDefaultValueBatchAtion;
import com.inspur.edp.bff.core.action.retrievedefault.RetrieveDefaultChildeWithIdsAction;
import com.inspur.edp.bff.core.action.save.SaveAction;
import com.inspur.edp.bff.core.entity.ViewObjectEntity;
import com.inspur.edp.bff.core.filter.BeforeHelpLinkConvertor;
import com.inspur.edp.bff.core.filter.FilterFieldConvertor;
import com.inspur.edp.bff.core.session.BffSessionItem;
import com.inspur.edp.bff.entity.RetrieveDefaultParam;
import com.inspur.edp.bff.entity.defaultvalue.VoDefaultValue;
import com.inspur.edp.bff.spi.AbstractBffEntityDeserConvertor;
import com.inspur.edp.bff.spi.AbstractBffEntitySerConvertor;
import com.inspur.edp.bff.spi.AbstractFSAction;
import com.inspur.edp.bff.spi.AbstractFSManager;
import com.inspur.edp.bff.spi.IHelpExtend;
import com.inspur.edp.bff.spi.VMHelpConfig;
import com.inspur.edp.bff.spi.builtin.BffEntityResInfoImpl;
import com.inspur.edp.bff.spi.changeset.AbstractBffChangeJsonDeserializer;
import com.inspur.edp.bff.spi.changeset.AbstractBffChangeJsonSerializer;
import com.inspur.edp.bff.spi.defaultvalue.VoBuiltInDefaultValueDeserializer;
import com.inspur.edp.bff.spi.defaultvalue.VoDefaultValueChildDeserializer;
import com.inspur.edp.bff.spi.event.query.BffQueryEventBroker;
import com.inspur.edp.bff.spi.event.retrievedefault.BffRetrieveDefaultEventBroker;
import com.inspur.edp.bff.spi.helpextend.VmLinkedConfig;
import com.inspur.edp.bff.spi.request.RequestConvertor;
import com.inspur.edp.bff.spi.response.ResponseConvertor;
import com.inspur.edp.bff.spi.utils.AuthUtils;
import com.inspur.edp.bff.spi.utils.ParameterInfo;
import com.inspur.edp.bff.spi.utils.ReflectInfo;
import com.inspur.edp.cdf.component.api.service.ComponentInvokeService;
import com.inspur.edp.cef.api.RefObject;
import com.inspur.edp.cef.api.action.EditResult;
import com.inspur.edp.cef.api.buffer.ICefBuffer;
import com.inspur.edp.cef.api.changeListener.EntityDataChangeListener;
import com.inspur.edp.cef.api.changeset.IChangesetManager;
import com.inspur.edp.cef.api.dataType.base.IEntityAccessorCreator;
import com.inspur.edp.cef.api.dataType.entity.ICefRootEntity;
import com.inspur.edp.cef.api.manager.IBufferManager;
import com.inspur.edp.cef.api.manager.serialize.CefSerializeContext;
import com.inspur.edp.cef.api.manager.serialize.JsonFormatType;
import com.inspur.edp.cef.api.repository.IRootRepository;
import com.inspur.edp.cef.api.request.RequestInfo;
import com.inspur.edp.cef.api.response.ResponseContext;
import com.inspur.edp.cef.api.response.ResponseInfo;
import com.inspur.edp.cef.api.response.viewrule.ViewRule;
import com.inspur.edp.cef.api.response.viewrule.ViewRuleFieldConfig;
import com.inspur.edp.cef.api.rootManager.IRootEntityCacheManager;
import com.inspur.edp.cef.api.rootManager.IRootManagerContext;
import com.inspur.edp.cef.api.session.ICefSession;
import com.inspur.edp.cef.api.session.ICefSessionItem;
import com.inspur.edp.cef.core.rootmanager.CefRootManager;
import com.inspur.edp.cef.entity.accessor.base.IAccessor;
import com.inspur.edp.cef.entity.changeset.IChangeDetail;
import com.inspur.edp.cef.entity.changeset.ValueObjModifyChangeDetail;
import com.inspur.edp.cef.entity.condition.EntityFilter;
import com.inspur.edp.cef.entity.condition.FilterCondition;
import com.inspur.edp.cef.entity.condition.SortCondition;
import com.inspur.edp.cef.entity.dependenceTemp.Pagination;
import com.inspur.edp.cef.entity.entity.ICefData;
import com.inspur.edp.cef.entity.entity.IEntityData;
import com.inspur.edp.cef.entity.entity.IValueObjData;
import com.inspur.edp.cef.spi.entity.info.CefEntityTypeInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.DataTypePropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.ObjectType;
import com.inspur.edp.cef.spi.entity.resourceInfo.ModelResInfo;
import com.inspur.edp.cef.spi.extend.datatype.ICefDataExtend;
import com.inspur.edp.cef.spi.extend.datatype.IDataExtendContainer;
import com.inspur.edp.cef.spi.extend.entity.ICefAddedChildDataExtend;
import com.inspur.edp.cef.spi.extend.entity.ICefAddedChildEntityExtend;
import com.inspur.edp.cef.spi.extend.entity.ICefEntityExtend;
import com.inspur.edp.cef.spi.jsonser.util.SerializerUtil;
import com.inspur.edp.cef.variable.api.manager.IVariableManager;
import com.inspur.edp.cef.variable.api.variable.IVariable;
import com.inspur.edp.commonmodel.core.session.distributed.SessionEditToken;
import com.inspur.edp.commonmodel.core.variable.VarBufferManager;
import com.inspur.edp.commonmodel.spi.AbstractEntityDataDeSerializer;
import com.inspur.edp.commonmodel.spi.AbstractEntityDataSerializer;
import com.inspur.edp.web.help.api.ILookupService;
import com.inspur.edp.web.help.api.LookupDataService;
import com.inspur.edp.web.help.api.LookupQueryParam;
import com.inspur.edp.web.help.api.LookupResult;
import com.inspur.edp.wf.bizprocess.entity.FormFormatConfig;
import com.inspur.edp.wf.bizprocess.service.FormFormatRpcService;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import io.iec.edp.caf.common.JSONSerializer;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.rpc.client.RpcClassHolder;
import io.iec.edp.caf.runtime.config.CefBeanUtil;
import lombok.var;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public abstract class FSManager extends CefRootManager implements IFSManager {

    private final static String FuncInstanceId = "Func-Inst-Id";
    private final Logger logger = LoggerFactory.getLogger(FSManager.class);
    private static List<String> rpcHelpList = new ArrayList<>();
    private static List<String> headers = Arrays.asList(FuncInstanceId);

    static {
        //bql帮助？
        rpcHelpList.add("47273c90-0a06-487f-a9d2-11e0fe902d90");
        rpcHelpList.add("802cebf2-fd97-445d-bdb7-e1d8150b1e4b");
        //业务种类元数据
        rpcHelpList.add("dad3612d-f7a9-4be8-8ce2-a1908c3dc42a");
    }

    private String funcSessionID;
    private IFSManagerContext context;
    private ResponseContext responseContext;
    private AbstractSourceConfig sourceConfigs = null;
    private String voType;
    private ArrayList<String> beTypes;
    private String voSessionKey;
    private ILookupService lookupService;
    private LookupDataService lookupDataService;
    private FormFormatRpcService formFormatRpcService;
    private List<IBffManagerExtend> extList = new ArrayList<>();
    private List<Class> extClassList = new ArrayList<>();
    private String funcInstanceId = null;
    private SessionEditToken locked;
    private TimeStampContext enableTimeStampLastModifiedBy;

    public FSManager(String funcSessionID) {
        this.funcSessionID = funcSessionID;
    }


    public FSManager() {
    }


    protected abstract String getVoId();

    public IFSManagerContext getBffContext() {
        if (context == null) {
            context = new FSManagerContext(this);
            context.setVoId(getVoId());
        }
        return context;
    }


    public final ResponseContext getResponseContext() {
        if (responseContext == null) {
            responseContext = new ResponseContext();
        }
        return responseContext;
    }

    public com.inspur.edp.cef.api.resourceInfo.ModelResourceInfos getModelResourceInfos() {
        return null;
    }

    @Override
    public ModelResInfo getModelInfo() {
        return null;
    }


    protected AbstractSourceConfig getSourceConfigs() {
        return null;
    }

    public AbstractSourceConfig getOutSourceConfigs() {
        if (sourceConfigs == null)
            sourceConfigs = getSourceConfigs();
        return sourceConfigs;
    }


    public final ArrayList<String> getBETypes() {
        return beTypes;
    }

    public final void setBETypes(ArrayList<String> value) {
        beTypes = value;
    }

    protected final <TResult> TResult executeAction(AbstractFSAction<TResult> action) {
        return ActionExecutor.executeAction(action, this, getBffContext());
    }

    protected final <TResult> TResult executeAction(AbstractFSAction<TResult> action, String actionId, String actionCode
            , Map<String, Object> parameters) {
        return executeAction(action, actionId, actionCode, parameters, false);
    }

    protected final <TResult> TResult executeAction(
            AbstractFSAction<TResult> action,
            String actionId,
            String actionCode,
            Map<String, Object> parameters, boolean autuSave) {
        return ActionExecutor.executeAction(action, this, getBffContext(), actionId, actionCode, parameters, autuSave);
    }

    public IVariableManager createVariableManager() {
        return null;
    }


    EditableBefSessionManager getBefSessionMgr() {
        return SpringBeanUtils.getBean(EditableBefSessionManager.class);
    }

    public final String connect(String parentSessionID) {
        if (funcInstanceId != null)
            synchronized (funcInstanceId.intern()) {
                return FuncSessionManager.getCurrent().initSessionWithToken(funcInstanceId);
            }
        return FuncSessionManager.getCurrent().initSessionWithToken(funcInstanceId);
    }

    public final void tryConnect() {
        Runnable action = () -> {
            if (FuncSessionManager.getCurrentFuncSessionId() == null) {
                String sessionId = FuncSessionManager.getCurrent().tryInitSessionWithToken(funcInstanceId);
                ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder
                        .getRequestAttributes();
                HttpServletResponse response = servletRequestAttributes.getResponse();
                response.addHeader("BEFSessionID", sessionId);
            }
        };
        if (funcInstanceId != null) {
            synchronized (funcInstanceId.intern()) {
                action.run();
            }
        } else {
            action.run();
        }
    }


    private String getVoSessionKey() {
        if (voSessionKey == null) {
            voSessionKey = "Vo_".concat(getVoId());
        }
        return voSessionKey;
    }

    public ICefSessionItem getCessionItem() {
        return tryGetAndAddSessionItem();
    }

    private ICefSessionItem tryGetAndAddSessionItem() {
        ICefSession session = FuncSessionManager.getCurrentSession();
        ICefSessionItem sessionItem = session.getSessionItems().get(getVoSessionKey());
        return sessionItem != null ? sessionItem : initSessionItem(session);
    }

    private ICefSessionItem initSessionItem(ICefSession session) {
        ICefSessionItem sessionItem = buildSessionItem(session);
        session.getSessionItems().put(getVoSessionKey(), sessionItem);
        return sessionItem;
    }

    public BffSessionItem buildSessionItem() {
        BffSessionItem item = new BffSessionItem(getVoSessionKey());
        item.setManager(this);
        IVariableManager varManager = createVariableManager();
        if (varManager != null) {
            VarBufferManager varBuffer = new VarBufferManager(item, varManager, getVoSessionKey());
            varBuffer.initBuffer();
            item.setVarBufferManager(varBuffer);
        }
        return item;
    }

    public BffSessionItem buildSessionItem(ICefSession session) {
        BffSessionItem item = new BffSessionItem((FuncSession) session, getVoSessionKey());
        item.setManager(this);
        IVariableManager varManager = createVariableManager();
        if (varManager != null) {
            VarBufferManager varBuffer = new VarBufferManager(item, varManager, getVoSessionKey());
            varBuffer.initBuffer();
            item.setVarBufferManager(varBuffer);
        }
        return item;
    }

    private IAccessor buildVariableAccessor(IVariableManager manager, IValueObjData data) {
        return manager.getAccessorCreator().createAccessor(data);
    }

    private IAccessor buildVariableReadOnlyAccessor(IVariableManager manager, IValueObjData data) {
        return manager.getAccessorCreator().createReadonlyAccessor(data);
    }

    public final void close() {
        String sessionId = FuncSessionManager.getCurrentFuncSessionId();
        if (StringUtils.isEmpty(sessionId)) {
            throw new BffFrameworkException(ErrorCodes.BFF_FRAMEWORK_1025);
        }
        FuncSessionManager.getCurrent().closeSessionWithToken(sessionId);
    }

    public final void cancel() {
        CancelAction action = FSActionFactory.getCancelAction();
        executeAction(action);
    }

    public final IEntityData retrieveDefault() {
        RetrieveDefaultAction action = FSActionFactory.getRetrieveDefaultAction();
        try {
            BffRetrieveDefaultEventBroker.fireBeforeRetrieveDefault(this, null, "");
            IEntityData data = executeAction(action, ActionConstant.RetrieveDefaultActionId, "RetrieveDefault", new HashMap<>(), false);
            BffRetrieveDefaultEventBroker.fireAfterRetrieveDefault(this, data);
            return data;
        } catch (Exception e) {
            BffRetrieveDefaultEventBroker.fireExceptionStop(e);
            throw new BffFrameworkException(e);
        }
    }

    public final IEntityData retrieveDefault(String dataId) {
        RetrieveDefaultAction action = FSActionFactory.getRetrieveDefaultAction(dataId);
        try {
            BffRetrieveDefaultEventBroker.fireBeforeRetrieveDefault(this, null, dataId);
            IEntityData data = executeAction(action, ActionConstant.RetrieveDefaultActionId, "RetrieveDefault", new HashMap<>(), false);
            BffRetrieveDefaultEventBroker.fireAfterRetrieveDefault(this, data);
            return data;
        } catch (Exception e) {
            BffRetrieveDefaultEventBroker.fireExceptionStop(e);
            throw new BffFrameworkException(e);
        }

    }

    public final IEntityData retrieveDefault(VoDefaultValue defaultValue) {
        RetrieveDefaultAction action = FSActionFactory.getRetrieveDefaultAction(defaultValue);
        try {
            BffRetrieveDefaultEventBroker.fireBeforeRetrieveDefault(this, defaultValue, "");
            IEntityData data = executeAction(action, ActionConstant.RetrieveDefaultActionId, "RetrieveDefault", new HashMap<>(), false);
            BffRetrieveDefaultEventBroker.fireAfterRetrieveDefault(this, data);
            return data;
        } catch (Exception e) {
            BffRetrieveDefaultEventBroker.fireExceptionStop(e);
            throw new BffFrameworkException(e);
        }

    }

    public final ArrayList<IEntityData> retrieveDefaultBatch(RetrieveDefaultParam defaultParam) {
        RetrieveDefaultBatchAction action = FSActionFactory.getRetrieveDefaultBatchAction(defaultParam);
        return executeAction(action, ActionConstant.RetrieveDefaultActionId, "BatchRetrieveDefault", new HashMap<>(), false);
    }

    public final IEntityData retrieveDefaultChild(ArrayList<String> nodeCodes, ArrayList<String> lierachyIds) {
        RetrieveDefaultChildAction action = FSActionFactory.getRetrieveDefaultChildAction(nodeCodes, lierachyIds);
        try {
            BffRetrieveDefaultEventBroker.fireBeforeRetrieveDefaultChild(this, nodeCodes, lierachyIds, null, null);
            IEntityData data = executeAction(action);
            BffRetrieveDefaultEventBroker.fireAfterRetrieveDefaultChild(this, new ArrayList<IEntityData>() {{
                add(data);
            }}, nodeCodes);
            return data;
        } catch (Exception e) {
            BffRetrieveDefaultEventBroker.fireExceptionStop(e);
            throw new BffFrameworkException(e);
        }
    }

    public final IEntityData retrieveDefaultChild(ArrayList<String> nodeCodes, ArrayList<String> lierachyIds, VoDefaultValue defaultValue) {
        RetrieveDefaultChildWithDefaultValueAtion action = FSActionFactory.getRetrieveDefaultChildWithDefaultValueAction(nodeCodes, lierachyIds, defaultValue);
        try {
            BffRetrieveDefaultEventBroker.fireBeforeRetrieveDefaultChild(this, nodeCodes, lierachyIds, null, new ArrayList<VoDefaultValue>() {{
                add(defaultValue);
            }});
            IEntityData data = executeAction(action);
            BffRetrieveDefaultEventBroker.fireAfterRetrieveDefaultChild(this, new ArrayList<IEntityData>() {{
                add(data);
            }}, nodeCodes);
            return data;
        } catch (Exception e) {
            BffRetrieveDefaultEventBroker.fireExceptionStop(e);
            throw new BffFrameworkException(e);
        }
    }

    public final ArrayList<IEntityData> retrieveDefaultChild(ArrayList<String> nodeCodes, ArrayList<String> lierachyIds,
                                                             RetrieveDefaultParam param) {
        RetrieveDefaultChildWithDefaultValueBatchAtion action = FSActionFactory.getRetrieveDefaultChildWithDefaultValueBatchAction(nodeCodes, lierachyIds, param);
        return executeAction(action);
    }

    public final ArrayList<IEntityData> retrieveDefaultChilds(ArrayList<String> nodeCodes, ArrayList<String> lierachyIds, ArrayList<VoDefaultValue> defaultValues) {
        MulitRetrieveDefaultWtihDefaultValueAction action = FSActionFactory.getMulitRetrieveDefaultWtihDefaultValueAction(nodeCodes, lierachyIds, defaultValues);
        try {
            BffRetrieveDefaultEventBroker.fireBeforeRetrieveDefaultChild(this, nodeCodes, lierachyIds, null, defaultValues);
            ArrayList<IEntityData> data = executeAction(action);
            BffRetrieveDefaultEventBroker.fireAfterRetrieveDefaultChild(this, data, nodeCodes);
            return data;
        } catch (Exception e) {
            BffRetrieveDefaultEventBroker.fireExceptionStop(e);
            throw new BffFrameworkException(e);
        }
    }

    public final ArrayList<IEntityData> retrieveDefaultChild(java.util.ArrayList<String> nodeCodes, java.util.ArrayList<String> lierachyIds, ArrayList<String> ids) {
        RetrieveDefaultChildeWithIdsAction action = FSActionFactory.getRetrieveDefaultChildWithIdsAction(nodeCodes, lierachyIds, ids);
        try {
            BffRetrieveDefaultEventBroker.fireBeforeRetrieveDefaultChild(this, nodeCodes, lierachyIds, ids, null);
            ArrayList<IEntityData> data = executeAction(action);
            BffRetrieveDefaultEventBroker.fireAfterRetrieveDefaultChild(this, data, nodeCodes);
            return data;
        } catch (Exception e) {
            BffRetrieveDefaultEventBroker.fireExceptionStop(e);
            throw new BffFrameworkException(e);
        }
    }

    public final IEntityData retrieve(String dataID) {
        RetrieveAction action = FSActionFactory.getRetrieveAction(dataID);
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("dataID", dataID);
        return executeAction(action, ActionConstant.RetrieveActionId, "Retrieve", parameters, false);
    }

    public final List<IEntityData> retrieve(ArrayList<String> dataIds, RetrieveParam retrieveParam) {
        MultiRetrieveAction action = FSActionFactory.getMultiRetrieveAction(dataIds, retrieveParam);
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("dataIds", dataIds);
        return executeAction(action, ActionConstant.RetrieveActionId, "Retrieve", parameters, false);
    }

    public final IEntityData retrieve(String dataId, RetrieveParam retrieveParam) {
        RetrieveAction action = FSActionFactory.getRetrieveAction(dataId, retrieveParam);
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("dataId", dataId);
        parameters.put("retrieveParam", retrieveParam);
        return executeAction(action, ActionConstant.RetrieveActionId, "Retrieve", parameters, false);
    }

    public final EditResult edit(String dataId) {
        EditAction action = FSActionFactory.getEditAction(dataId);
        return executeAction(action);
    }

    public final IEntityData retrieveChild(ArrayList<String> nodeCodes, ArrayList<String> lierachyIds, RetrieveParam retrieveParam) {
        //TODO 临时处理，后续改造成Action
//        return getBffContext().getLcp().retrieveChild(nodeCodes, lierachyIds, retrieveParam).getData();
        RetrieveChildAction retrieveChildAction = FSActionFactory.getRetrieveChildAction(nodeCodes, lierachyIds, retrieveParam);
        return executeAction(retrieveChildAction);
    }

    public final ArrayList<IEntityData> retrieveChild(ArrayList<String> nodeCodes, ArrayList<String> lierachyIds, ArrayList<String> ids, RetrieveParam retrieveParam) {
        //TODO 临时处理，后续改造成Action
//        return getBffContext().getLcp().retrieveChild(nodeCodes, lierachyIds, retrieveParam).getData();
        RetrieveChildAndChildAction retrieveChildAction = FSActionFactory.getRetrieveChildAndChildAction(nodeCodes, lierachyIds, ids, retrieveParam);
        return executeAction(retrieveChildAction);
    }

    public final void modify(IChangeDetail change) {
        ModifyAction action = FSActionFactory.getModifyAction(change);
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("change", change);
        executeAction(action, ActionConstant.ModifyActionId, "Modify", parameters, false);
    }

    public final QueryResult query(EntityFilter filter) {
        QueryResult result = new QueryResult();
        try {
            BffQueryEventBroker.fireBeforeQuery(getBffContext(), filter, null);
            Map<String, Object> parameters = new HashMap<>();
            parameters.put("filter", filter);
            //TODO 临时修改，后续添加filter的克隆功能。
            ArrayList<SortCondition> sorts = filter.getSortConditions();
            copyFilter(filter);
            QueryAction action = FSActionFactory.getQueryAction(filter);
            ArrayList<IEntityData> queryresult = executeAction(action, ActionConstant.QueryActionId, "Query", parameters, false);
            filter.setSortConditions(sorts);
            result.setResult(queryresult);
            result.setPagination(filter.getPagination());
            BffQueryEventBroker.fireAfterQuery(getBffContext(), filter, queryresult);
        } catch (Exception e) {
            BffQueryEventBroker.fireQueryUnnormalStop(e);
            throw e;
        }
        return result;
    }

    public final QueryResult queryChild(List<String> nodeCodes, EntityFilter filter) {
        QueryResult result = new QueryResult();
        ArrayList<SortCondition> sorts = filter.getSortConditions();
        copyFilter(filter);
        QueryChildAction action = FSActionFactory.getQueryChildAction(nodeCodes, filter);
        ArrayList<IEntityData> queryresult = executeAction(action);
        filter.setSortConditions(sorts);
        result.setResult(queryresult);
        result.setPagination(filter.getPagination());
        return result;
    }

    public final QueryResult queryChild(String nodeCode, EntityFilter filter) {
        QueryResult result = new QueryResult();
        ArrayList<SortCondition> sorts = filter.getSortConditions();
        copyFilter(filter);
        QueryChildWithCodeAction action = FSActionFactory.getQueryChildWithCodeAction(nodeCode, filter);
        ArrayList<IEntityData> queryresult = executeAction(action);
        filter.setSortConditions(sorts);
        result.setResult(queryresult);
        result.setPagination(filter.getPagination());
        return result;
    }

    private void copyFilter(EntityFilter filter) {
        ArrayList<SortCondition> sorts = filter.getSortConditions();
        if (sorts == null || sorts.size() < 1)
            return;
        filter.setSortConditions(new ArrayList<>());
        for (SortCondition sort : sorts) {
            SortCondition newSort = new SortCondition(sort.getSortField(), sort.getSortType());
            filter.getSortConditions().add(newSort);
        }
    }

    public final QueryResult queryWithAuthInfo(EntityFilter filter, AuthInfo authInfo) {
        QueryResult queryResult;
        try {
            BffQueryEventBroker.fireBeforeQuery(getBffContext(), filter, authInfo);
            queryResult = new QueryResult();
            QueryWithAuthInfoAction authInfoAction = FSActionFactory.getQueryWithAuthInfoAction(filter, authInfo);
            ArrayList<IEntityData> qresult = executeAction(authInfoAction);
            queryResult.setResult(qresult);
            queryResult.setPagination(filter.getPagination());
            BffQueryEventBroker.fireAfterQuery(getBffContext(), filter, qresult);
        } catch (Exception e) {
            BffQueryEventBroker.fireQueryUnnormalStop(e);
            throw e;
        }
        return queryResult;
    }

    public final List<IEntityData> query(String param, Pagination pageInfo, String extendCond) {

        return null;
    }

    public final void delete(String dataID) {
        DeleteAction action = FSActionFactory.getDeleteAction(dataID);
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("dataID", dataID);
        executeAction(action, ActionConstant.DeleteActionId, "Delete", parameters, false);
    }

    public final void delete(ArrayList<String> dataIds) {

        MultiDeleteAction action = FSActionFactory.getMultiDeleteAction(dataIds);
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("dataIDs", dataIds);
        executeAction(action, ActionConstant.DeleteActionId, "Delete", parameters, false);
    }

    public final void deleteAndSave(String dataID) {
        DeleteAndSaveAction action = FSActionFactory.getDeleteAndSaveAction(dataID);
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("dataID", dataID);
        executeAction(action, ActionConstant.DeleteAndSaveActionId, "DeleteAndSave", parameters, false);
    }

    public final void deleteChild(List<String> nodeCodes, List<String> hierachyIdList, List<String> ids) {

        DeleteChildAction action = FSActionFactory.getDeleteChildAction(nodeCodes, hierachyIdList, ids);
        executeAction(action);
    }

    public final void save() {

        SaveAction action = FSActionFactory.getSaveAction();
        Map<String, Object> parameters = new HashMap<>();
        executeAction(action, ActionConstant.SaveActionId, "Save", parameters, false);
    }

    //TODO 確認是否已經不需要了
    protected abstract IChangeConvertor getChangeMapConvertor();

    protected abstract IDataConvertor getDataConvertor();

    protected IFilterFieldConvertor getFilterConvertor() {
        return new FilterFieldConvertor(this);
    }

    protected IDefaultValueConvertor getDefaultValueConvertor() {
        return null;
    }

    protected abstract IEntityData innerCreateData();

    protected abstract IEntityData innerCreateChildData(String childCode);


    public IAssemblerManager getAssemblerManager() {
        return null;
    }

    public final IEntityData createData(String dataID) {
        IEntityData entity = innerCreateData();
        entity.setID(dataID);
        tryAddExtend2RootData(entity);
        return (IEntityData) getAccessorCreator().createAccessor(entity);
    }

    //原CreateData抽象方法改名为CreateDataCore
    public final IEntityData createData() {
        IEntityData entity = innerCreateData();
        tryAddExtend2RootData(entity);
        return (IEntityData) getAccessorCreator().createAccessor(entity);
    }

    //原CreateChilData抽象方法改名为CreateChilDataCore
    public final IEntityData createChilData(String childCode) {
        return createChildData(childCode, null);
    }

    public final IEntityData createChildData(String childCode, String dataID) {
        if (getExtList() != null) {
            for (IBffManagerExtend ext : getExtList()) {

                ICefAddedChildEntityExtend added = ext.getAddedChildEntity(childCode);
                if (added == null) {
                    continue;
                }
                ICefAddedChildDataExtend dataExtend = added.getDataExtend();
                IEntityData data = (IEntityData) dataExtend.createData();
                data.setID(dataID);
                return (IEntityData) dataExtend.createAccessor(data);
            }
        }
        IEntityData childEntity = innerCreateChildData(childCode);
        if (childEntity instanceof IDataExtendContainer && getExtList() != null) {
            for (IBffManagerExtend mgrExt : getExtList()) {
                ICefEntityExtend childEntityExt = mgrExt.getChildEntityExtend(childCode);
                if (childEntityExt == null) {
                    continue;
                }
                ICefDataExtend dataExt = childEntityExt.getDataExtend();
                if (dataExt == null) {
                    continue;
                }
                ((IDataExtendContainer) childEntity).addExtend(dataExt);
            }
        }
        childEntity.setID(dataID);
        return (IEntityData) ((IEntityAccessorCreator) getAccessorCreator()).createChildAccessor(childCode, childEntity);
    }

    public IEntityData createUnlistenableData(String dataID) {
        IEntityData entity = innerCreateData();
        entity.setID(dataID);
        tryAddExtend2RootData(entity);
        return entity;
    }


    public IEntityData createUnlistenableChildData(String childCode, String dataID) {
        IEntityData childEntity = innerCreateChildData(childCode);
        if (childEntity instanceof IDataExtendContainer && getExtList() != null) {
            for (IBffManagerExtend ext : getExtList()) {

                ICefAddedChildEntityExtend added = ext.getAddedChildEntity(childCode);
                if (added == null) {
                    continue;
                }
                ICefAddedChildDataExtend dataExtend = added.getDataExtend();
                IEntityData data = (IEntityData) dataExtend.createData();
                data.setID(dataID);
                return data;
            }

        }

        if (childEntity instanceof IDataExtendContainer && getExtList() != null) {
            for (IBffManagerExtend mgrExt : getExtList()) {
                ICefEntityExtend childEntityExt = mgrExt.getChildEntityExtend(childCode);
                if (childEntityExt == null) {
                    continue;
                }
                ICefDataExtend dataExt = childEntityExt.getDataExtend();
                if (dataExt == null) {
                    continue;
                }
                ((IDataExtendContainer) childEntity).addExtend(dataExt);
            }
        }
        childEntity.setID(dataID);

        return childEntity;
    }

    protected abstract AbstractBffEntitySerConvertor getDataJsonSerizlize();

    protected abstract AbstractBffEntityDeserConvertor getDataJsonDeSerizlize();

    private ObjectMapper getEntityJsonMapper(boolean keepAssoPropertyForExpression) {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        var extList = getExtList().stream().map(item -> item.getDataTypeExtend())
                .filter(item -> item != null).collect(Collectors.toList());

        AbstractBffEntitySerConvertor dataJsonSerizlize = getDataJsonSerizlize();
        extList.forEach(item -> dataJsonSerizlize.addExtend(item));
        module.addSerializer(ICefData.class, dataJsonSerizlize);
        if (keepAssoPropertyForExpression) {
            dataJsonSerizlize.setCefSerializeContext(CefSerializeContext.getSerContextKeepAssoPropertyForExpression());
        }

        AbstractBffEntityDeserConvertor dataJsonDeSerizlize = getDataJsonDeSerizlize();
        extList.forEach(item -> dataJsonDeSerizlize.addExtend(item));
        dataJsonDeSerizlize.setManager(this);
        module.addDeserializer(createData().getClass(), dataJsonDeSerizlize);

        mapper.registerModule(module);
        return mapper;
    }

    private ObjectMapper getEntityJsonMapper(List<String> nodeCodes) {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        AbstractEntityDataSerializer serializer = getDataJsonSerizlize().getChildDataConvertor((String) nodeCodes.get(0));
        AbstractEntityDataDeSerializer deSerializer = getDataJsonDeSerizlize().getChildDataConvertor((String) nodeCodes.get(0));
        for (int i = 1; i < nodeCodes.size(); i++) {
            serializer = serializer.getChildDataConvertor((String) nodeCodes.get(i));
            deSerializer = deSerializer.getChildDataConvertor((String) nodeCodes.get(i));
        }
        module.addSerializer(ICefData.class, serializer);
        module.addDeserializer(createChilData((String) nodeCodes.get(nodeCodes.size() - 1)).getClass(), deSerializer);
        mapper.registerModule(module);
        return mapper;
    }

    public final String serializeData(List<String> nodeCodes, IEntityData data) {
        try {
            return getEntityJsonMapper(nodeCodes).writeValueAsString(data);
        } catch (JsonProcessingException e) {
            throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_1026);
        }
    }

    public final IEntityData deserializeData(List<String> nodeCodes, String serializedData) {
        try {
            IEntityData data = (IEntityData) getEntityJsonMapper(nodeCodes).readValue(serializedData, createChilData((String) nodeCodes.get(nodeCodes.size() - 1)).getClass());
            return (IEntityData) ((IEntityAccessorCreator) getAccessorCreator()).createChildAccessor((String) nodeCodes.get(nodeCodes.size() - 1), data);
        } catch (IOException e) {
            throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_1027);
        }
    }

    @Override
    public final String serializeDataForExpression(IEntityData data) {
        try {
            SerializerUtil.isKeepAssoPropertyForExpression().set("1");
            return getEntityJsonMapper(true).writeValueAsString(data);
        } catch (JsonProcessingException e) {
            throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_1026);
        } finally {
            SerializerUtil.isKeepAssoPropertyForExpression().remove();
        }
    }

    public final String serializeData(IEntityData data) {
        try {
            return getEntityJsonMapper(false).writeValueAsString(data);
        } catch (JsonProcessingException e) {
            throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_1026);
        }
    }

    public final IEntityData deserializeData(String serializedData) {
        try {
            IEntityData data = getEntityJsonMapper(false).readValue(serializedData, createData().getClass());
            return (IEntityData) getAccessorCreator().createAccessor(data);
        } catch (IOException e) {
            throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_1027);
        }
    }

    @Override
    public String serializeChanges(List<IChangeDetail> arrayList) {
        try {
            return getChangeJsonMapper().writeValueAsString(arrayList);
        } catch (JsonProcessingException e) {
            throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_1028);
        }
    }

    @Override
    public ArrayList<IChangeDetail> deserializeChanges(String strChange) {
        ArrayList<IChangeDetail> changeDetails = null;
        try {
            var mapper = getChangeJsonMapper();
            JavaType type = mapper.getTypeFactory().
                    constructCollectionType(ArrayList.class, IChangeDetail.class);
            changeDetails = mapper.readValue(strChange, type);
        } catch (IOException e) {
            throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_1029);
        }
        return changeDetails;
    }

    protected abstract AbstractBffChangeJsonSerializer getChangeSerializer();

    protected abstract AbstractBffChangeJsonDeserializer getChangeDeserializer();

    private ObjectMapper getChangeJsonMapper() {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        var extList = getExtList().stream().map(item -> item.getDataTypeExtend())
                .filter(item -> item != null).collect(Collectors.toList());

        AbstractBffChangeJsonSerializer ser = getChangeSerializer();
        extList.forEach(item -> ser.addExtend(item));
        module.addSerializer(IChangeDetail.class, ser);

        var deSer = getChangeDeserializer();
        extList.forEach(item -> deSer.addExtend(item));
        deSer.setManager(this);
        deSer.setCefSerializeContext(new CefSerializeContext());
        module.addDeserializer(IChangeDetail.class, deSer);

        mapper.registerModule(module);
        return mapper;
    }

    public final String serializeChange(IChangeDetail change) {

        try {
            return getChangeJsonMapper().writeValueAsString(change);
        } catch (JsonProcessingException e) {
            throw new BffFrameworkException(e);
        }

    }

    public final IChangeDetail deserializeChange(String strChange) {

        try {
            return getChangeJsonMapper().readValue(strChange, IChangeDetail.class);
        } catch (IOException e) {
            throw new BffFrameworkException(e);
        }
    }


    protected abstract String getBECodeFromVM(String vmObjectCode);

    protected abstract String getVMCodeFromBE(String beObjectCode);

    //子类实现
    protected IEntityPropertyMapper getRootEntityPropertyMapper() {
        return null;
    }


    protected final void setContext(AbstractFSManager mgr) {
        mgr.setContext(this.getBffContext());
    }

    public final LookupResult getElementHelp(String codeName, String labelId, String queryParam) {
        LookupQueryParam target = null;
        if (!StringUtils.isEmpty(queryParam)) {
            try {
                target = new ObjectMapper().readValue(queryParam, LookupQueryParam.class);
            } catch (IOException e) {
                throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_1030);
            }
        }
        if (target == null) {
            target = new LookupQueryParam();
        }

        return getElementHelp(codeName, labelId, target);
    }


    private ILookupService getLookupService() {
        if (lookupService == null) {
            lookupService = CefBeanUtil.getAppCtx().getBean(ILookupService.class);
        }
        return lookupService;
    }


    private LookupDataService getLookupDataService() {
        if (lookupDataService == null) {
            lookupDataService = CefBeanUtil.getAppCtx().getBean(LookupDataService.class);
        }
        return lookupDataService;
    }

    public final LookupResult getElementHelp(String codeName, String labelId,
                                             LookupQueryParam queryParam) {
        Objects.requireNonNull(codeName);
        Objects.requireNonNull(labelId);

        String helpId = null;
        //TODO 目前由于项目问题，临时修改先走扩展再走基，后续需要讨论
        VMHelpConfig helpConfig = FSManagerExtendUtil.getHelpConfig(getExtList(), codeName, labelId);
        if (helpConfig == null) {
            helpConfig = getHelpConfig(codeName, labelId);
        }
        if (helpConfig == null) {//发现一些很老的基础字典没有生成getHelpConfig方法, 在这里兼容
            helpId = getHelpId(codeName, labelId);
            if (getHelpActions(codeName, labelId).size() > 0) {
                for (IHelpExtend item : getHelpActions(codeName, labelId)) {
                    ((AbstractFSAction<VoidActionResult>) item).deal(getBffContext());
                    item.beforeHelp(queryParam);
                }
            }
        } else {
            helpId = helpConfig.getHelpId();

            ArrayList<ReflectInfo> actionRecord = helpConfig.getActionRecord();
            ComponentInvokeService componentInvokeService = SpringBeanUtils.getBean(ComponentInvokeService.class);
            if (actionRecord != null) {
                for (ReflectInfo item : actionRecord) {
                    if (item.getParameterInfoList() != null && !item.getParameterInfoList().isEmpty()) {
                        List<Object> parameters = new ArrayList<>(1);
                        parameters.add(item.getParameterInfoList());
                        IHelpExtend instance;
                        if (item.getComponentID() != null && !item.getComponentID().isEmpty()) {
                            instance = (IHelpExtend) componentInvokeService.getInstance(item.getComponentID(), parameters);
                        } else {
                            instance = (IHelpExtend) createInstance(item.getClassName(), item.getParameterInfoList());
                        }
                        ((AbstractFSAction<VoidActionResult>) instance).deal(getBffContext());
                        instance.beforeHelp(queryParam);
                    } else {
                        IHelpExtend instance;
                        if (item.getComponentID() != null && !item.getComponentID().isEmpty()) {
                            instance = (IHelpExtend) componentInvokeService.getInstance(item.getComponentID());
                        } else {
                            instance = (IHelpExtend) createInstance(item.getClassName());
                        }
                        ((AbstractFSAction<VoidActionResult>) instance).deal(getBffContext());
                        instance.beforeHelp(queryParam);
                    }
                }
            }
            if (helpConfig != null && helpConfig.getUseCustomAuthInfo() && queryParam != null) {
                queryParam.setAuthInfo(new AuthInfo());
                queryParam.getAuthInfo().setExtType("VoHelp");
                queryParam.getAuthInfo().setExtend1(helpConfig.getVoID());
                queryParam.getAuthInfo().setExtend2(helpConfig.getHelpElementID());
            }
        }
        buildLinkedConfig(this, helpConfig, queryParam);
        //直接走rpc有风险(项目业务对象是否正确部署?)
        if (isRpcHelp(helpId)) {
            return getLookupDataService().getData(helpId, queryParam);
        }
        return getLookupService().getData(helpId, queryParam);
    }

    private boolean isRpcHelp(String helpId) {
        if (rpcHelpList.contains(helpId)) {
            return true;
        }
        return false;
    }

    private void buildLinkedConfig(IFSManager manager, VMHelpConfig helpConfig, LookupQueryParam param) {
        if (helpConfig == null || helpConfig.getLinkedConfigs() == null || helpConfig.getLinkedConfigs().size() == 0)
            return;
        List<VmLinkedConfig> linkedConfigs = helpConfig.getLinkedConfigs();
        for (VmLinkedConfig linkedConfig : linkedConfigs) {
            BeforeHelpLinkConvertor.beforeHelpQuery(this, helpConfig, linkedConfig, param);
        }
    }

    private List<Object> getCompParams(List<ParameterInfo> parameterInfoList) {
        List<Object> parameters = new ArrayList<>(parameterInfoList.size());
        for (ParameterInfo parameterInfo : parameterInfoList) {
            parameters.add(parameterInfo.getParameterValue());
        }
        return parameters;
    }

    protected VMHelpConfig getHelpConfig(String codeName, String labelId) {
        return null;
    }

    protected Object createInstance(String classFullName) {
        try {
            Class c = Class.forName(classFullName);
            return c.getConstructor((Class[]) null).newInstance((Object[]) null);
        } catch (InstantiationException
                 | IllegalAccessException
                 | InvocationTargetException
                 | NoSuchMethodException
                 | ClassNotFoundException e) {
            throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_1031, classFullName);
        }
    }

    protected Object createInstance(String classFullName, List<ParameterInfo> parameterInfoList) {
        try {
            Class c = Class.forName(classFullName);
            return c.getConstructor(new Class[]{java.util.List.class}).newInstance(parameterInfoList);
        } catch (InstantiationException
                 | IllegalAccessException
                 | InvocationTargetException
                 | NoSuchMethodException
                 | ClassNotFoundException e) {
            throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_1031, classFullName);
        }
    }

    protected abstract String getHelpId(String codeName, String labelId);

    protected ArrayList<IHelpExtend> getHelpActions(String codeName, String labelId) {
        return new ArrayList<IHelpExtend>();
    }

    public java.lang.Class getDefaultValueType() {
        return null;
    }

    public java.lang.Class getChangeInfoType() {
        return null;
    }

    public java.lang.Class getRequsetType() {
        return null;
    }

    public ResponseInfo createResponse() {
        return null;
    }

    public RequestInfo buildRequest(String requestStr, CefSerializeContext context) {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        RequestConvertor deSer = getRequestConvertor();
        deSer.setContext(context);
        List<IBffEntityExtend> extList = getExtList().stream().map(IBffManagerExtend::getDataTypeExtend)
                .filter(Objects::nonNull).collect(Collectors.toList());
        deSer.setExtList(extList);

        module.addDeserializer(RequestInfo.class, deSer);
        mapper.registerModule(module);
        RequestInfo requestInfo;
        try {
            requestInfo = mapper.readValue(requestStr, RequestInfo.class);
        } catch (IOException e) {
            throw new BffFrameworkException(e);
        }
        if (requestInfo != null && requestInfo.getDataChange() != null && !requestInfo.getDataChange().isEmpty()) {
            checkRequestDataChange(requestStr);
        }
        return requestInfo;
    }

    protected RequestConvertor getRequestConvertor() {
        //此默认实现，为了兼容原有生成的代码，
        Class requestType = getRequsetType();
        var annotation = (JsonDeserialize) requestType.getAnnotation(JsonDeserialize.class);
        if (annotation == null)
            throw new BffFrameworkException(ErrorCodes.BFF_FRAMEWORK_1032);
        var convertorType = annotation.using();
        try {
            return (RequestConvertor) convertorType.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new BffFrameworkException(ErrorCodes.BFF_FRAMEWORK_1033, convertorType.getName());
        }
    }

    public final void dealRequest(RequestInfo request) {
        if (request == null) {
            return;
        }
        SessionEditToken token = null;
        if (getBefSessionMgr().getCurrentSessionId() != null) {
            token = getBefSessionMgr().beginEdit();
        }
        try {
            if (request.getDataChange() != null && request.getDataChange().size() > 0) {
                for (IChangeDetail changeDetail : request.getDataChange()) {
                    modify(changeDetail);
                }
            }

            if (request.getVariableChange() != null) {
                dealVariable(request.getVariableChange());
            }
        } finally {
            if (token != null)
                getBefSessionMgr().endEdit(token);
        }
    }

    /**
     * 根据界面规则检查变更集中是否对不可编辑字段做了修改（未检查整条数据的删除操作）
     *
     * @throws BffFrameworkException 若变更集中对不可编辑字段做了修改
     */
    private void checkRequestDataChange(String requestJson) {
        if (((BffSessionItem) getCessionItem()).getViewRule() == null) {
            return;
        }
        List<String> unchangeableFieldsJsonPath = this.getOrCreatedUnchangeableFieldsJsonPath(((BffSessionItem) getCessionItem()).getViewRule());
        if (unchangeableFieldsJsonPath.isEmpty()) {
            return;
        }
        DocumentContext requestJsonDoc = JsonPath.parse(requestJson);
        String jsonPathPrefix = "$.dataChange.[*].";

        unchangeableFieldsJsonPath.forEach(
                fieldJsonPath -> {
                    String jsonPath = jsonPathPrefix + fieldJsonPath;
                    try {
                        Object result = requestJsonDoc.read(jsonPath);
                        // read方法中，若没有该节点时，一类会抛出异常，一类会返回空集合，取决于匹配符匹配到了哪一层
                        // read没抛异常而且返回的不是空集合，表示变更集中有该节点，抛异常
                        if (!(result instanceof Collection && ((Collection<?>) result).isEmpty())) {
                            throw new BffFrameworkException(ErrorCodes.BFF_FRAMEWORK_3001, jsonPath);
                        }
                    } catch (PathNotFoundException pathNotFoundException) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("jsonPath:{} not found in responseJson:{}", jsonPath, requestJson, pathNotFoundException);
                        }
                    }
                });
    }

    /**
     * 获取或者生成界面规则中不可编辑字段的JsonPath
     */
    @Nonnull
    private List<String> getOrCreatedUnchangeableFieldsJsonPath(ViewRule viewRule) {
        BffSessionItem bffSessionItem = ((BffSessionItem) getCessionItem());
        if (bffSessionItem.getUnchangeableFieldsJsonPathInDataChange() != null) {
            return bffSessionItem.getUnchangeableFieldsJsonPathInDataChange();
        }
        List<String> unchangeableFieldsJsonPath = new ArrayList<>();
        bffSessionItem.setUnchangeableFieldsJsonPathInDataChange(unchangeableFieldsJsonPath);

        List<ViewRuleFieldConfig> fieldConfigs = viewRule.getFieldConfigs();
        if (fieldConfigs == null || fieldConfigs.isEmpty()) {
            return unchangeableFieldsJsonPath;
        }
        List<ViewRuleFieldConfig> unchangeableFields = fieldConfigs.stream()
                .filter(ViewRuleUtil::isUnchangeable)
                .collect(Collectors.toList());
        if (unchangeableFields.isEmpty()) {
            return unchangeableFieldsJsonPath;
        }
        ModelResInfo modelResInfo = this.getModelInfo();
        unchangeableFields.forEach(
                fieldConfig ->
                        unchangeableFieldsJsonPath.add(
                                ViewRuleUtil.buildJsonPathInDataChange(
                                        fieldConfig,
                                        getFieldObjectType(fieldConfig, modelResInfo)))
        );
        return unchangeableFieldsJsonPath;
    }

    /**
     * 获取界面规则中字段的ObjectType
     */
    @Nonnull
    private ObjectType getFieldObjectType(ViewRuleFieldConfig fieldConfig, ModelResInfo modelResInfo) {
        String nodeCode;
        try {
            // 获取节点编号，主表或子表
            if (StringUtils.isEmpty(fieldConfig.getNodeCode())) {
                nodeCode = modelResInfo.getRootNodeCode();
            } else {
                String[] nodeCodes = fieldConfig.getNodeCode().split("\\.");
                nodeCode = nodeCodes[nodeCodes.length - 1];
            }
            // 获取字段编号
            String fieldName = fieldConfig.getId().split("\\.")[0];
            // 获取节点类型
            BffEntityResInfoImpl bffEntityResInfo = (BffEntityResInfoImpl) modelResInfo.getCustomResource(nodeCode);
            CefEntityTypeInfo entityTypeInfo = bffEntityResInfo.getEntityTypeInfo();
            DataTypePropertyInfo dataTypePropertyInfo = entityTypeInfo.getPropertyInfo(fieldName);
            if (dataTypePropertyInfo.getObjectType() == null) {
                throw new BffFrameworkException(ErrorCodes.BFF_FRAMEWORK_3002, fieldConfig.getNodeCode(), fieldConfig.getId());
            }
            return dataTypePropertyInfo.getObjectType();
        } catch (RuntimeException e) {
            throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_3002, fieldConfig.getNodeCode(), fieldConfig.getId());
        }

    }


    public final void dealVariable(IChangeDetail change) {
        IVariableManager varManager = createVariableManager();
        //TODO 发版后放开
//        if(varManager == null)
//            throw new RuntimeException(getVoType()+"中没有设置变量，不允许写入变量值");

        IValueObjData data = (IValueObjData) ((tryGetAndAddSessionItem().getVariableBuffers().get(0).getData()));
        Object tempVar = varManager.createValueObject(data);
        IVariable variableEntity = (IVariable) ((tempVar instanceof IVariable) ? tempVar : null);

        EntityDataChangeListener listener = tryGetAndAddSessionItem().getVarListener();
        listener.suspend();
        try {
            variableEntity.modify(change);
            addViewRuleToSession(change);
            getResponseContext().setVariableInnerChange(variableEntity.getVariableContext().getInnerChange());
        } finally {
            listener.resume();
        }

    }

    /**
     * 若变量中有流程实例信息，则获取流程配置的界面规则结果添加到session及responseContext中
     *
     * @param change 变量变更
     */
    private void addViewRuleToSession(@Nonnull IChangeDetail change) {
        if (!(change instanceof ValueObjModifyChangeDetail)
                || ((ValueObjModifyChangeDetail) change).getPropertyChanges() == null) {
            return;
        }
        Object formConfigIdObj = ((ValueObjModifyChangeDetail) change).getPropertyChanges().get("bffSysFormConfigId");
        if (formConfigIdObj == null) {
            return;
        }
        String formConfigId = formConfigIdObj.toString();
        ((BffSessionItem) getCessionItem()).setViewRule(getViewRuleFromWF(formConfigId));
        this.getResponseContext().setViewRule(((BffSessionItem) getCessionItem()).getViewRule());
    }

    @Nonnull
    private ViewRule getViewRuleFromWF(@Nonnull String formConfigId) {
        FormFormatRpcService formatRpcService = this.getFormFormatRpcService();
        FormFormatConfig formFormatConfig = formatRpcService.getFormFormatConfig(formConfigId);
        // 输出debug日志便于出错时调试
        if (logger.isDebugEnabled()) {
            try {
                logger.debug("获取界面规则：" + new ObjectMapper().writeValueAsString(formFormatConfig));
            } catch (JsonProcessingException e) {
                logger.debug("序列化界面规则结果失败", e);
            }
        }
        return ViewRuleUtil.getViewRule(formFormatConfig);
    }

    private FormFormatRpcService getFormFormatRpcService() {
        if (this.formFormatRpcService != null) {
            return this.formFormatRpcService;
        }
        RpcClassHolder rpcClassHolder = SpringBeanUtils.getBean(RpcClassHolder.class);
        this.formFormatRpcService = rpcClassHolder.getRpcClass(FormFormatRpcService.class);
        return this.formFormatRpcService;
    }

    public final ResponseInfo buildResponse(Object returnValue) {
        ResponseInfo response = createResponse();
        response.setReturnValue(returnValue);
        response.setInnerDataChange(getResponseContext().getInnerChangeset());
        response.setMessage(getResponseContext().getMessages());
        response.setInnerVariableChange(getResponseContext().getVariableInnerChange());
        response.setViewRule(getResponseContext().getViewRule());
        return response;
    }

    public final ICefData getVariableData() {
        ICefBuffer buffer = tryGetAndAddSessionItem().getVariableBuffers().get(0);
        return buffer.getData();
    }

    public final EntityDataChangeListener getVariableListener() {
        return tryGetAndAddSessionItem().getVarListener();
    }


    @Override
    public IRootRepository getRepository() {
        return null;
    }

    public final IEntityData createDataType() {
        return createData();
    }

    @Override
    public String serialize(ICefData data) {
        return serializeData((IEntityData) data);
    }

    @Override
    public ICefData deserialize(String content) {
        return deserializeData(content);
    }

    @Override
    protected IRootManagerContext createRootManagerContext() {
        FSManagerContext fsContext = new FSManagerContext(this);
        fsContext.setVoId(getVoId());
        return fsContext;
    }

    @Override
    protected IRootEntityCacheManager createEntityCacheManager() {
        return null;
    }

    @Override
    protected IBufferManager createBufferManager() {
        return null;
    }

    @Override
    protected final IChangesetManager createChangesetManager() {
        return null;
    }

    @Override
    protected final ICefRootEntity newEntity(String id) {
        var entity = (ViewObjectEntity) createVoEntity(id);
        if (extList != null) {
            entity.setExtend(
                    extList.stream().map(item -> item.getDataTypeExtend()).filter(item -> item != null)
                            .collect(Collectors.toList()));
        }
        return entity;
    }

    protected abstract ICefRootEntity createVoEntity(String id);


    List<IBffManagerExtend> getExtList() {
        return extList;
    }


    public List<Class> getExtClassList() {
        return extClassList;
    }

    protected void addExtClass(Class extClass) {
        extClassList.add(extClass);
    }

    public void addExtend(IBffManagerExtend ext) {
        Objects.requireNonNull(ext, "ext");
        extList.add(ext);
    }

    protected void tryAddExtend2RootData(ICefData data) {
        if (!(data instanceof IDataExtendContainer)) {
            return;
        }
        if (extList.isEmpty()) {
            return;
        }
        IDataExtendContainer container = (IDataExtendContainer) data;
        for (IBffManagerExtend mgrExt : extList) {
            IBffEntityExtend dataTypeExtend = mgrExt.getDataTypeExtend();
            if (dataTypeExtend == null) {
                continue;
            }
            IBffEntityDataExtend dataExt = dataTypeExtend.getDataExtend();
            if (dataExt == null) {
                continue;
            }
            container.addExtend(dataExt);
        }
    }

    public String getVoType() {
        if (voType == null)
            voType = getModelResourceInfos().getModelDispalyName();
        return voType;
    }

    public void setVoType(String voType) {
        this.voType = voType;
    }

    public String getVoNodeCode(String frontNodeCode) {
        return null;
    }

    @Override
    public RetrieveResult retrieveWithChildPagination(String
                                                              dataId, com.inspur.edp.bff.api.param.retrieve.RetrieveParam param) {
        RetrieveWithChildPaginationAction action = FSActionFactory.getRetrieveWithChildPagination(dataId, param);
        return executeAction(action);
    }

    @Override
    public RetrieveChildResult retrieveChildByIndex
            (ArrayList<String> nodeCodes, ArrayList<String> hierachyIds, Pagination pagination) {
        RetrieveChildByIndexAction action = FSActionFactory.getRetrieveChildByIndexAction(nodeCodes, hierachyIds, pagination);
        return executeAction(action);
    }


    public Object executeCustomAction(String actionCode, LinkedHashMap<String, Object> params) {

        RefObject<Object> result = new RefObject<>(new Object());
        for (IBffManagerExtend mgrExt : extList) {
            boolean hasExecute = mgrExt.invokeAction(actionCode, result, (FSManagerContext) getBffContext(), params);
            if (hasExecute)
                return result.argvalue;

        }
        throw new BffFrameworkException(ErrorCodes.BFF_FRAMEWORK_1034, actionCode);
    }

    public void deleteAndSave(ArrayList<String> dataIds) {
        getBffContext().getLcp().atomicallyInvoke(() -> {
            delete(dataIds);
            save();
        });
    }

    public boolean isEngine() {
        return false;
    }

    /**
     * 解析型ResponseInfo序列化调用
     *
     * @return 序列化结果
     */
    public String serializeResponseInfo(ResponseInfo responseInfo, CefSerializeContext context) {
        ObjectMapper mapper;
        try {
            mapper = JSONSerializer.getObjectMapper().copy();
            ResponseConvertor convertor = getResponseConvertor();
            if (convertor != null && (context != null && context.getJsonFormatType() == JsonFormatType.Tiled)) {
                SimpleModule module = new SimpleModule();
                setResponseExtList(convertor, this.getExtList());
                convertor.setContext(context);
                module.addSerializer(responseInfo.getClass(), convertor);
                mapper.registerModule(module);
                mapper.configure(MapperFeature.USE_ANNOTATIONS, false);
            }
            return filterResponseJson(mapper.writeValueAsString(responseInfo), responseInfo, context);
        } catch (JsonProcessingException e) {
            throw new BffFrameworkException(e);
        }
    }

    /**
     * 根据界面规则过滤掉“returnValue”中需隐藏的字段，仅支持JsonFormatType.Normal的JSON
     *
     * @param responseJson     未过滤隐藏字段的原始JSON字符串
     * @param responseInfo     responseJson对应的序列化前的对象
     * @param serializeContext 序列化上下文
     * @return 当序列化类型是JsonFormatType.Normal时，返回过滤掉隐藏字段的JSON字符串。否则返回原始JSON字符串
     */
    protected final String filterResponseJson(String responseJson, ResponseInfo responseInfo, CefSerializeContext serializeContext) {
        if (((BffSessionItem) getCessionItem()).getViewRule() == null
                || responseInfo.getReturnValue() == null) {
            return responseJson;
        }
        // 非Normal格式，直接返回
        if (serializeContext != null && serializeContext.getJsonFormatType() != JsonFormatType.Normal) {
            return responseJson;
        }
        List<String> hiddenFieldsJsonPath = this.getOrCreatedHiddenFieldsJsonPath(((BffSessionItem) getCessionItem()).getViewRule());
        if (hiddenFieldsJsonPath.isEmpty()) {
            return responseJson;
        }
        DocumentContext responseJsonDoc = JsonPath.parse(responseJson);
        String jsonPathPrefix = "$.returnValue.";
        if (responseInfo.getReturnValue() instanceof QueryResult
                || responseInfo.getReturnValue() instanceof RetrieveResult
                || responseInfo.getReturnValue() instanceof RetrieveChildResult) {
            jsonPathPrefix += "result.[*].";
        }
        String finalJsonPathPrefix = jsonPathPrefix;

        hiddenFieldsJsonPath.forEach(
                fieldJsonPath -> {
                    String jsonPath = finalJsonPathPrefix + fieldJsonPath;
                    try {
                        responseJsonDoc.delete(jsonPath);
                    } catch (PathNotFoundException pathNotFoundException) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("jsonPath:{} not found in responseJson:{}", jsonPath, responseJson, pathNotFoundException);
                        }
                    }
                });
        return responseJsonDoc.jsonString();
    }

    /**
     * 获取或者生成界面规则中隐藏字段的JSONPath
     */
    @Nonnull
    private List<String> getOrCreatedHiddenFieldsJsonPath(ViewRule viewRule) {
        BffSessionItem bffSessionItem = ((BffSessionItem) getCessionItem());
        if (bffSessionItem.getHiddenFieldsJsonPathInResult() != null) {
            return bffSessionItem.getHiddenFieldsJsonPathInResult();
        }
        List<String> hiddenFieldsJsonPath = new ArrayList<>();
        bffSessionItem.setHiddenFieldsJsonPathInResult(hiddenFieldsJsonPath);

        List<ViewRuleFieldConfig> fieldConfigs = viewRule.getFieldConfigs();
        if (fieldConfigs == null || fieldConfigs.isEmpty()) {
            return hiddenFieldsJsonPath;
        }
        List<ViewRuleFieldConfig> hiddenFields = fieldConfigs.stream()
                .filter(ViewRuleUtil::isHidden)
                .collect(Collectors.toList());
        if (hiddenFields.isEmpty()) {
            return hiddenFieldsJsonPath;
        }
        hiddenFields.forEach(
                fieldConfig ->
                        hiddenFieldsJsonPath.add(ViewRuleUtil.buildJsonPathInResult(fieldConfig))
        );
        return hiddenFieldsJsonPath;
    }

    private void setResponseExtList(ResponseConvertor convertor, List<IBffManagerExtend> bffManagerExtends) {
        if (bffManagerExtends == null || bffManagerExtends.size() == 0)
            return;
        ArrayList<IBffEntityExtend> bffEntityExtends = new ArrayList<>();
        for (IBffManagerExtend managerExtend : this.getExtList()) {
            bffEntityExtends.add(managerExtend.getDataTypeExtend());
        }
        if (bffEntityExtends.size() > 0) {
            convertor.setExtList(bffEntityExtends);
        }
    }

    protected ResponseConvertor getResponseConvertor() {
        return null;
    }


    public ArrayList<IChangeDetail> convertChangefromVo(ArrayList<IChangeDetail> voChanges) {
        ChangeMapperContext mapperContext = new ChangeMapperContext();
        mapperContext.setSourceChange(voChanges);
        getAssemblerManager().getChangeMapperAssembler().doChangeMappingFromVo(getBffContext(), mapperContext);
        return mapperContext.getMappedChange().values().stream().findFirst().get();
    }

    public ArrayList<IChangeDetail> convertChange2Vo(ArrayList<IChangeDetail> sourceChanges) {
        ArrayList<IChangeDetail> voChanges = new ArrayList<IChangeDetail>();
        IChangeConvertor convertor = getChangeMapConvertor();
        for (IChangeDetail sourceChange : sourceChanges) {
            IChangeDetail voChange = convertor.convertFromBEChange(sourceChange);
            voChanges.add(voChange);
        }
        return voChanges;
    }


    @Override
    public IEntityData createAndSave(IEntityData data) {
        IStandardLcp lcp = (IStandardLcp) getBffContext().getLcp();
        IEntityData beData = lcp.createUnlistenableData(data.getID());
        getBffContext().getDataConvertor().convertFromVMData(data, beData);
        beData = lcp.retrieveDefault(beData);
        lcp.save();
        return retrieve(beData.getID());
    }

    @Override
    public IEntityData modifyAndSave(IEntityData data) {
        IStandardLcp lcp = (IStandardLcp) getBffContext().getLcp();
        IEntityData beData = lcp.createUnlistenableData(data.getID());
        getBffContext().getDataConvertor().convertFromVMData(data, beData);
        lcp.modify(beData);
        lcp.save();
        return retrieve(data.getID());
    }


    @Override
    public List<String> getAcceptHeaderNames() {
        return headers;
    }

    @Override
    public void setHeader(String name, String value) {
        Objects.requireNonNull(name, "name");
        switch (name) {
            case FuncInstanceId:
                setFuncInstanceId(value);
                break;
        }
    }


    public void setFuncInstanceId(String id) {
        this.funcInstanceId = id;
    }


    @Override
    public void onBeforeRequest() {
        locked = getBefSessionMgr().getCurrentSessionId() != null ? getBefSessionMgr().beginEdit()
                : null;
    }

    @Override
    public void onFinallyRequest() {
        if (locked == null) {
            return;
        }
        getBefSessionMgr().endEdit(locked);
    }

    /**
     * @param nodeCodes 除主表外，从上级到下级的节点编号
     * @param nodeJson  前端传过来的json串
     * @return
     */
    public ArrayList<VoDefaultValue> deserializeVoDefaultValues(List<String> nodeCodes, String nodeJson) {
        if (nodeCodes == null || nodeCodes.size() == 0) {
            return deserializeVoDefaultValues(nodeJson);
        }
        VoDefaultValueChildDeserializer deserializer = new VoDefaultValueChildDeserializer(getBffContext().getBffManager(), (ArrayList<String>) nodeCodes);
        ArrayList<VoDefaultValue> voDefaultValues;
        try {

            ObjectMapper mapper = getDefaultValueMapper(deserializer);
            JavaType type = mapper.getTypeFactory().
                    constructCollectionType(ArrayList.class, VoDefaultValue.class);
            voDefaultValues = mapper.readValue(nodeJson, type);
        } catch (IOException e) {
            throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_1035);
        }

        return voDefaultValues;
    }

    public ArrayList<VoDefaultValue> deserializeVoDefaultValues(String nodeJson) {
        VoBuiltInDefaultValueDeserializer deserializer = new VoBuiltInDefaultValueDeserializer(getBffContext().getBffManager());
        ArrayList<VoDefaultValue> voDefaultValues;
        try {

            ObjectMapper mapper = getDefaultValueMapper(deserializer);
            JavaType type = mapper.getTypeFactory().
                    constructCollectionType(ArrayList.class, VoDefaultValue.class);
            voDefaultValues = mapper.readValue(nodeJson, type);
        } catch (IOException e) {
            throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_1035);
        }

        return voDefaultValues;
    }

    public VoDefaultValue deserializeVoDefaultValue(List<String> nodeCodes, String nodeJson) {
        if (nodeCodes == null)
            return deserializeVoDefaultValue(nodeJson);
        VoDefaultValueChildDeserializer deserializer = new VoDefaultValueChildDeserializer(getBffContext().getBffManager(), (ArrayList<String>) nodeCodes);
        VoDefaultValue voDefaultValue;
        try {
            voDefaultValue = getDefaultValueMapper(deserializer).readValue(nodeJson, VoDefaultValue.class);
        } catch (IOException e) {
            throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_1035);
        }

        return voDefaultValue;
    }

    public VoDefaultValue deserializeVoDefaultValue(String nodeJson) {
        VoBuiltInDefaultValueDeserializer deserializer = new VoBuiltInDefaultValueDeserializer(getBffContext().getBffManager());
        VoDefaultValue voDefaultValue;
        try {
            voDefaultValue = getDefaultValueMapper(deserializer).readValue(nodeJson, VoDefaultValue.class);
        } catch (IOException e) {
            throw new BffFrameworkException(e, ErrorCodes.BFF_FRAMEWORK_1035);
        }

        return voDefaultValue;
    }

    private ObjectMapper getDefaultValueMapper(VoBuiltInDefaultValueDeserializer deserializer) {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(VoDefaultValue.class, deserializer);
        mapper.registerModule(module);
        return mapper;
    }

    public RetrieveDefaultParam deserializerRetrieveDefaultParam(String nodeJson) {
        return deserializerRetrieveDefaultParam(null, nodeJson);
    }

    public RetrieveDefaultParam deserializerRetrieveDefaultParam(List<String> nodeCodes, String nodeJson) {
        ObjectMapper mapper = new ObjectMapper();
        RetrieveDefaultParam param = new RetrieveDefaultParam();
        try {
            JsonNode node = mapper.readTree(nodeJson);

            ArrayList<VoDefaultValue> defaultValues = deserializeVoDefaultValues(nodeCodes, node.get("defaultValues").toString());
            param.getVoDefaultValues().addAll(defaultValues);
            return param;
        } catch (IOException e) {
            throw new BffFrameworkException(ErrorCodes.BFF_FRAMEWORK_1036);
        }
    }


    public TimeStampContext getTimeStampContext() {
        if (this.enableTimeStampLastModifiedBy == null) {
            this.enableTimeStampLastModifiedBy = new TimeStampContext();
        }
        return this.enableTimeStampLastModifiedBy;
    }

    public void setTimeStampContext(TimeStampContext value) {
        this.enableTimeStampLastModifiedBy = value;
    }

    public final List<String> getDistinctFJM(String fjnPropertyName, EntityFilter filter, Integer
            parentLayer, AuthInfo authInfo) {
        if (getBffContext().getFilterConvertor() != null) {
            fjnPropertyName = getBffContext().getFilterConvertor().transFilterField(fjnPropertyName);
            if (filter.getFilterConditions() != null)
                for (FilterCondition filterCondition : filter.getFilterConditions()) {
                    filterCondition.setFilterField(getBffContext().getFilterConvertor().transFilterField(filterCondition.getFilterField()));
                }
            if (filter.getSortConditions() != null)
                for (SortCondition sortCondition : filter.getSortConditions()) {
                    sortCondition.setSortField(getBffContext().getFilterConvertor().transFilterField(sortCondition.getSortField()));
                }
        }

        IStandardLcp lcp = getBffContext().getLcp();
        if (authInfo != null && authInfo.getExtType() != null && "".equals(authInfo.getExtType()) == false) {
            AuthUtils.buildAuthInfo(
                    lcp.getBefContext().getAuthInfo(),
                    authInfo.getExtType(),
                    authInfo.getExtend1(),
                    authInfo.getExtend2(),
                    authInfo.getExtend3(),
                    authInfo.getExtend4(),
                    authInfo.getExtend5()
            );
        }
        return lcp.getDistinctFJM(fjnPropertyName, filter, parentLayer);
    }

    public final boolean hasChanges() {
        IStandardLcp lcp = getBffContext().getLcp();
        return lcp.hasChanges();
    }
}
